<template>
  <div style="width:300px" :key="uuid">
    <el-popover :placement="placement" :width="popoverWidth" popper-class="ele-select-load"
      :visible="popoverShow" @after-leave="onPopoverHidden">
      <template #reference>
        <el-input ref="mainInputRef" debounce="500" :model-value="inputShowValue" :disabled="disabled"
          :readonly="readonly" :key="uuid" :placeholder="placeholder" @click="onClickInput"
          @update:model-value="onInput">
          <template #suffix>
            <!-- 清空按钮 -->
            <el-icon v-if="clearableBtn" class="page-input-icon " color="#ff6b6bcc" :size="16"
              @click.stop="clearableValue">
              <circle-close />
            </el-icon>
            <!-- 箭头按钮 -->
            <el-icon v-else class="page-input-icon page-input-icon-xx" :class="{ 'page-input-icon-xs': popoverShow }"
              @click.stop="onClickInput">
              <arrow-down />
            </el-icon>
          </template>
        </el-input>
      </template>
      <div ref="selectLoadPopoverRef" v-loading="loading || selectLoading">
        <!-- @update:model-value="emit('update:searchValue', $event)"
        -->
        <div v-if="isPaging" class="page-table-header">
          <el-input placeholder="请输入查询字段" size="small" style="width:200px" v-model="searchValue"
            @keyup.enter.native="resetGetData">
            <template #append>
              <el-button size="small" :icon="Search" @click="resetGetData"></el-button>
            </template>
          </el-input>
        </div>
        <el-table class="page-table" :data="selectList" ref="peopoverTable" size="small" max-height="250"
          highlight-current-row :current-row-key="code" :row-class-name="rowClassName" @row-click="rowClick">
          <el-table-column type="index" label="#" width="50" v-if="$slots['table-column'] && !hiddenIndex">
          </el-table-column>
          <slot name="table-column">
            <el-table-column :prop="code" label="编号" width="60"></el-table-column>
            <el-table-column :prop="name" label="名称" min-width="100"></el-table-column>
          </slot>
        </el-table>

        <el-pagination v-if="isPaging" style="margin-top:3px" v-model:currentPage="currentPage" :pager-count="5" small
          background layout="pager,jumper" :total="total" :page-size="pageSize" @current-change="resetGetData" />
      </div>
    </el-popover>
  </div>
</template>

<script lang="ts" >
import { defineComponent, watch } from "vue";
export default defineComponent({
  name: "SelectLoad"
});
</script>

<script lang="ts" setup>
import { withDefaults, ref, computed, reactive, onBeforeUnmount, nextTick, onMounted, } from "vue";
import { onClickOutside, useMouseInElement } from '@vueuse/core';
import { Search, CircleClose, ArrowDown } from '@element-plus/icons-vue'
import { v4 } from "uuid";
import LoginVue from "@/views/Login/Login.vue";


let props = withDefaults(defineProps<{
  /**
   * 输入值
   */
  modelValue?: string | number;

  /**
   * 是否被禁用
   */
  disabled?: boolean;

  /**
  弹框的显示位置
   */
  placement?: "top" | "top-start" | "top-end" | "bottom" | "bottom-start" | "bottom-end" | "left" | "left-start" | "left-end" | "right" | "right-start" | "right-end";

  /**
   * 提示话术
   */
  placeholder?: string;

  /**
 * 是否可以自定义输入内容
 */
  customInput?: boolean;

  /**
   * 是否可以清空选项
   */
  clearable?: boolean;


  /**
 * 默认是Name和Code下方传递的code和name可用来指定哪个字段为code或者name
 */
  code?: string;

  /**
 *  自定义业务Name
 */
  name?: string;

  /**
  自定义展示格式
  这个需要传入的方法，参数是row
  这个方法必须有有一个string类型返回值，用作展示。
  注意：当同时使用nameValue的时候，需要对nameValue传入的进行相同的处理
  不然nameValue会覆盖输入框的
  */
  displayFormat?: ((item: any) => string) | undefined;

  /**
 * 静态传入的列表数据
 */
  staticList?: any[];

  /**
   * 是否可以筛选
   */
  filterable?: boolean;

  /**
   * 是否可以创建新选项
   */
  allowCreate?: boolean;

  /**
   * 是否开启搜索
   * 默认为开启
   */
  isSearch?: boolean;

  /**
 * 开启强制更新
 * 是每次获取焦点都加载（默认不是每次都加载）
 * 默认为false
 */
  forceUpdate?: boolean;

  /**
   * 加载中
   */
  loading?: boolean;

  /**
   * 自定义远程获取事件
   * 传入参数
   * {
   *    search: 当前搜索框数据
   *    page:当前页数
   *    limit:每页的数量
   * }
   * 这个事件必须返回一个Promise
   * 返回的数据中需要提供
   * {
   *    dataList:数据列表
   *    total:数据个数
   * }
   */
  remoteMethod?: ((para: {
    search: string,
    page: number,
    limit: number
  }) => Promise<{ dataList: any[], total?: number }>) | undefined

  /**
   * 模糊搜索字数限制,达到这个字数才会触发搜索
   */
  wordLimit?: number;

  /**
 *是否加载分页数据
 */
  isPaging?: boolean;

  /**
   * 分页时候一页加载的条数
   */
  limit?: number;

  /**
  * 传入的name值(输入框展示值)
  * 这个通常用在分页列表中
  */
  nameValue?: string;

  /**
   * 是否隐藏index 列
   */
  hiddenIndex?: boolean;
  /**
   * 弹窗宽度
   */
  popoverWidth?: string
}>(), {
  modelValue: "",
  disabled: false,
  placement: "bottom-start",
  placeholder: "请选择",
  customInput: false,
  clearable: false,
  code: "code",
  name: "name",
  staticList: () => [],
  isSearch: true,
  forceUpdate: false,
  wordLimit: 0,
  isPaging: false,
  limit: 25,
  nameValue: "",
  hiddenIndex: false,
  loading: false,
  allowCreate: false,
  filterable: false,
  popoverWidth: ""
})

let emit = defineEmits<{
  /**
   * 更改外部数据
   */
  (e: "update:modelValue", value: string | number): void
  /**
  * 更改外部传入的初始值
  */
  (e: "update:nameValue", value: string): void
  /**
   * 当选项发生变化时候
   */
  (e: "change", value: any, prop: {
    allowCreate?: boolean
  }): void;
  /**
   * 选项发生变化的时候
   * 仅用户触发
   */
  (e: "select", value: any, prop: {
    allowCreate?: boolean
  }): void
}>()

/**
 * 内部是否启动页面loading
 */
let selectLoading = ref(false);

onBeforeUnmount(() => {
  stopHandle && stopHandle();
  stopHandle = null;
})

let uuid = ref<string>(v4());

/**
* ========================
* input框相关数据
*=========================
 */

/**
 * 箭头图表
 */
let xxIcon = require("@/assets/icon/xx.svg");

/**
 * 组件内计算input框数据
 */
let inputValue = ref<string | number>("");

/**
 * 当input 可以输入的时候, input 输入的返回值
 */
let inputWriteValue = ref<string>("");

/**
 * input组件
 */
let mainInputRef = ref();


/**
 * 鼠标是否再input框之外
 */
const { isOutside } = useMouseInElement(mainInputRef);

/**
 * 当前input 框是否为只读
 */
let readonly = computed(() => { return !props.allowCreate });

/**
 * 清空按钮是否展示
 */
let clearableBtn = computed(() => { return props.clearable && inputShowValue.value && !isOutside.value });

/**
 * input  框实际展示数据
 */
let inputShowValue = computed<string>(() => {
  if (!readonly.value && inputWriteValue.value) {
    return inputWriteValue.value;
  } else if (inputValue.value) {
    return inputValue.value;
  } else if (props.nameValue) {
    return props.nameValue;
  } else if (props.modelValue) {
    let selectItem = selectList.value.find((item: any) => {
      return item[props.code] == props.modelValue
    });
    if (selectItem) {
      return selectItem[props.name]
    } else {
      return props.modelValue;
    }
  } else {
    return ""
  }
})

/**
 * 当用户数据值的时候
 */
function onInput(value: string) {
  if (!readonly.value && props.allowCreate) {
    inputWriteValue.value = value;
    emit("update:modelValue", inputWriteValue.value);
    let row = {
      [props.code]: inputWriteValue.value,
      [props.name]: "",
    }
    emit("change", row, {
      allowCreate: true
    });
    emit("select", row, {
      allowCreate: true
    })
  }
}

/**
 * 当点击input框的时候
 */
function onClickInput() {
  if (popoverShow.value || stopHandle) return;

  // 打开弹框
  if (props.remoteMethod) {
    //当存在获取远程数据的时候 才进行获取数据
    if (props.forceUpdate) {
      //开启强制更新的时候，每次获取焦点都将更新数据
      resetGetData();
    } else {
      //如果有缓存数据 就会用缓存数据
      getData();
    }
  }
  openPopover();
}

/**
 * 清空数据
 */
function clearableValue() {
  //清空选择值
  onSelectItem({});
  //清空table选择
  if (peopoverTable.value) {
    peopoverTable.value.setCurrentRow();
  }
  //如果有自定义输入的,清空输入值
  if (!readonly.value) inputWriteValue.value = "";
}

/**
 * 当input框获得焦点的时候
 */
function onFocus() {
}

/**
* ========================
* 弹框
*=========================
 */

/**
 * 弹框是否展示
 */
let popoverShow = ref(false);

/**
 * 弹框ref
 */
let selectLoadPopoverRef = ref();

/**
 * 弹框关闭
 */
let stopHandle: any;

// watch(popoverShow, (value: boolean) => {
//   console.log(value);
//   if (value) {
//     //这里直接使用 延时时间其实更为简单 , 否则需要多个事件共同进行计算
//     //这里也没法获取到 element组件内部的一些数据
//     setTimeout(() => {

//     }, 300)
//   } else {
//     stopHandle && stopHandle();
//     stopHandle = null;
//   }
// })

/**
 * 打开弹框
 */
function openPopover() {
  popoverShow.value = true;
  nextTick(() => {
    stopHandle = onClickOutside(selectLoadPopoverRef, (event) => {
      closePopover();
    });
  })
}

/**
 * 关闭弹框
 */
function closePopover() {
  popoverShow.value = false;
  if (mainInputRef.value) mainInputRef.value.blur();
  stopHandle && stopHandle();
}

/**
 * 当弹框的隐藏动画播放完成后触发
 */
function onPopoverHidden() {
  stopHandle = null;
}

/**
* ========================
* 弹框内部数据
*=========================
 */

/**
 * 弹框表格
 */
let peopoverTable = ref();

/**
*下拉框实际展示内容
*/
let selectList = computed<any[]>(() => {
  if (props.remoteMethod) {
    return remoteDataList.value
  } else {
    return props.staticList
  }
});

/**
 * 表示远程数据是否已经加载
 */
let isLoadRemote: boolean = false;

/**
 * 保存的远程数据
 */
let remoteDataList = ref<any[]>([]);

/**
 * 分页时候的查询
 */
let searchValue = ref("");

/**
 * 每页查询数量
 */
let pageSize = ref(25);

/**
 * 分页的时候当前页数
 */
let currentPage = ref<number>(1);

/**
 * 分页数据中总数居
 */
let total = ref(0);

/**
 * 行回调
 */
function rowClassName(prop: { row: any; rowIndex: number }) {
  if (prop.row.Status != 0 && prop.row.Status) {
    return 'classColor'
  }
  return "";
}

/**
 * 这个表示只要值发生更改就会调用
 */
function onChange(row: any) {
  // props.nameValue = ""
  emit("update:nameValue", "")
  //赋值到input框上
  inputValue.value = props.displayFormat
    ? props.displayFormat(row)
    : row[props.name] || "";

  //将传进来的初始名称清空

  // //赋值到thisNameValue上
  // this.thisNameValue = this.inputValue;

  let defaultValue: string | number = "";
  if (typeof props.modelValue == "number") {
    defaultValue = 0;
  }

  //赋值到外部
  emit("update:modelValue", row[props.code] || defaultValue)
  emit("change", row, {});
}

/**
 * 这个表示是由用户触发行为
 * 选择某个项目的时候
 */
function onSelectItem(row: any) {
  if (!readonly.value) {
    inputWriteValue.value = "";
  }
  onChange(row);
  emit("select", row, {});
  //弹框隐藏
  closePopover();
}

/**
 * 当点击某一行的时候 
 */
function rowClick(row: any) {
  onSelectItem(row);
}

/**
 * 重新获取数据
 */
function resetGetData() {
  isLoadRemote = false;
  getData();
}

/**
 * 获取远程数据
 */
function getData() {
  //远程数据只会获取一次，除非调用重新获取数据
  if (isLoadRemote) return;
  isLoadRemote = true;
  if (props.remoteMethod) {
    selectLoading.value = true;
    //不存在远程方法 , 则就使用静态数据
    props.remoteMethod({
      search: searchValue.value,
      page: currentPage.value,
      limit: pageSize.value
    }).then((data) => {
      remoteDataList.value = data.dataList;
      total.value = data.total || 0;
    })
      .finally(() => {
        selectLoading.value = false;
      })
  }
}



/**
* ========================
* 组件初始化
*=========================
 */

if (props.remoteMethod && !props.isPaging) {
  //对于远程数据非分页数据 , 我们直接获取数据
  getData();
}

defineExpose({
  resetGetData
})

</script>

<style lang="less">
.ele-select-load {
  padding: 3px !important;
}
</style>

<style lang="less" scoped>
.page-input-icon {
  width: 14px;
  height: 100%;
  background-repeat: no-repeat;
  background-size: contain;
  background-position: center;
}

.page-input-icon-xx {
  transition: 0.25s;
}

.page-input-icon-xs {
  transform: rotate(-180deg);
}

.page-table-header {
  padding: 3px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

.page-table {
  /deep/ .el-table__body tr {
    cursor: pointer;
  }

  /deep/ .el-table__body tr.current-row>td.el-table__cell {
    font-weight: bold;
    color: var(--primaryColor);
  }


}

/deep/ .classColor {
  color: red !important;
}
</style>